package com.wtzz.police.base.util;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.KeyValue;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.SessionFactory;
import org.hibernate.query.NativeQuery;
import org.hibernate.type.EnumType;
import org.hibernate.type.Type;
import org.springframework.beans.BeanUtils;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.Transient;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import java.util.Properties;

public interface RepoHelper {

    default String generateAndConditions(List<String> conditions, String connector) {
        if (CollectionUtils.isEmpty(conditions)) {
            return "";
        } else {
            StringBuilder sqlBuilder = new StringBuilder(" ");
            for (int i = 0; i < conditions.size(); i++) {
                sqlBuilder.append(i == 0 ? connector : "and").append(" ").append(conditions.get(i)).append(" ");
            }
            return sqlBuilder.toString();
        }
    }

    default String generateOrConditions(List<String> conditions, String connector) {
        if (CollectionUtils.isEmpty(conditions)) {
            return "";
        } else {
            StringBuilder sqlBuilder = new StringBuilder(" ");
            for (int i = 0; i < conditions.size(); i++) {
                sqlBuilder.append(i == 0 ? connector : "or").append(" ").append(conditions.get(i)).append(" ");
            }
            return sqlBuilder.toString();
        }
    }

    default Query bindParams(Query query, List<KeyValue<String, Object>> params) {
        if (CollectionUtils.isEmpty(params)) {
            return query;
        } else {
            for (KeyValue<String, Object> param : params) {
                query.setParameter(param.getKey(), param.getValue());
            }
            return query;
        }
    }

    default NativeQuery addScalarToQuery(NativeQuery query, Class targetClazz) {
        PropertyDescriptor[] properties = BeanUtils.getPropertyDescriptors(targetClazz);
        for (PropertyDescriptor property : properties) {
            String name = property.getName();
            Field f = FieldUtils.getDeclaredField(targetClazz, name, true);
            if (f == null) f = FieldUtils.getField(targetClazz, name, true);
            if (f != null && !f.isAnnotationPresent(Transient.class)) {
                query.addScalar(name);
            }
        }
        return query;
    }

    default Type createEnumTypeScale(EntityManager em, Class enumClass, boolean enumTypeAsString) {
        Properties p = new Properties();
        p.put("enumClass", enumClass.getName());
        p.put("type", enumTypeAsString ? "12" : "4"); /*EnumType.STRING type = 12 */ /*EnumType.ORDINAL type = 4 */
        return em.getEntityManagerFactory().unwrap(SessionFactory.class).getTypeHelper().custom(EnumType.class, p);
    }

    default String wrapLike(String key) {
        return "%" + key + "%";
    }

    default String wrapSingleQuote(String key) {
        return "'" + key + "'";
    }

    default String wrapBracket(String content) {
        return " (" + content + ") ";
    }

    default String wrapSpace(String content) {
        return " " + content + " ";
    }

    default String wrapSelectCount(String dataSql, String alias) {
        return "SELECT COUNT(*) FROM " + wrapBracket(dataSql) + " " + wrapSpace(alias);
    }

    default <T> T getFirstResult(List resultList) {
        if (CollectionUtils.isNotEmpty(resultList)) {
            return IterableUtils.first((List<T>) resultList);
        }
        return null;
    }

    default Date parseDate(String dateText) {
        if (StringUtils.isEmpty(dateText)) {
            return null;
        }
        try {
            return DateUtils.parseDate(dateText, "yyyy-MM-dd", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss");
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    default Date addDays(Date date, int amount) {
        if (date == null) return null;
        else return DateUtils.addDays(date, amount);
    }

}
